package tss.client;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.StringTokenizer;

import tss.common.Connection;
import tss.common.Protocol;
import tss.common.*;

public class ClientConnection extends Connection {

	private int extensionNumber = -1;
	private ExtensionStates[] extensionStates = null;
	private LineStates lineState = LineStates.Connecting;
	private Client service = null;
	private SelectionKey key = null;
	
	public ClientConnection(Client service) throws Exception {
		super();
		if (service == null)
			throw new Exception("Service can not be null.");
			
		this.service = service;
	}
	
	public void connectToServer(String host, int port) throws IOException {
		super.connectClient(host, port);
	}
	
	public int getExtensionNumber() { return extensionNumber; }
	public LineStates getLineState() { return lineState; }

	@Override
	protected void onAccept(SelectionKey key) throws Exception {
		throw new Exception("Not Supported.");
	}

	@Override
	protected void onConnect(SelectionKey key) throws Exception {
		write(Protocol.MSG_REGISTER_REQ, key);
	}

	@Override
	protected void onDisconnect(SelectionKey key) {
		// TODO Auto-generated method stub
	}

	@Override
	protected void onRead(String packet, SelectionKey key) {
		this.key = key;
		SocketChannel channel = (SocketChannel)key.channel();

		String opt = null;
		String lineEnd =  System.getProperty("line.separator");	
		StringTokenizer tokens = new StringTokenizer(packet," "+lineEnd);
		
		opt = tokens.nextToken();
		
		//notify(address, "Requests -> " + opt);
		if (opt.equals(Protocol.MSG_REGISTER_ACK)) {
			extensionNumber = Integer.parseInt(tokens.nextToken()); 
			this.lineState = LineStates.Open;
		}
		else if (opt.equals(Protocol.MSG_LIST_ACCOUNTS)) {
			parseExtensionStates(tokens);
		}
		else if (opt.equals(Protocol.MSG_CALL_RING)) {
			this.lineState = LineStates.Ringing;
		}
		else if (opt.equals(Protocol.MSG_CALL_NOLINES) || opt.equals(Protocol.MSG_CALL_UNAVAILABLE)) {
			this.lineState = LineStates.Error;
		}
		else if (opt.equals(Protocol.MSG_CALL_BUSY)) {
			this.lineState = LineStates.Busy;
		}
		else if (opt.equals(Protocol.MSG_CALL_TALKING)) {
			this.lineState = LineStates.Talking;
		}
		else if (opt.equals(Protocol.MSG_CALL_DISCONNECT)) {
			this.lineState = LineStates.Open;
		}
			
		synchronized(service) { service.notify(); }
	}

	public void requestExtensionStates() {
		write(Protocol.MSG_LIST_ACCOUNTS, key);
	}
	
	private void parseExtensionStates(StringTokenizer tokens) {
		int extensionCount = tokens.countTokens();
		
		extensionStates = new ExtensionStates[extensionCount];
		for (int i = 0; i < extensionCount; i++) {
			extensionStates[i] = ExtensionStates.valueOf(tokens.nextToken());
		}
	}

	public ExtensionStates[] getExtensionStates() {
		return this.extensionStates;
	}
	
	
	public void callExtension(int extension) {
		write(Protocol.MSG_CALL_REQ + " " + extension, key);
	}
	
	public void acceptConnection() {
		write(Protocol.MSG_CALL_ACCEPT, key);
	}

	public void terminateConnection() {
		write(Protocol.MSG_CALL_DISCONNECT, key);
	}
	
	
	public void disconnect() {
		try {
			super.disconnect(this.key);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
